package com.daji.concurrency.multithread_synchronized;

//该代码接B01,是B01的加锁版本
public class B02_Synchronized {
    public static void main(String[] args) throws Exception {
        Thread add = new Thread(()->{
            for (int i=0; i<10000; i++) {
                //Java程序使用synchronized关键字对一个对象进行加锁.被加锁的是个对象
                synchronized(Counter0.lock) {   //获取锁
                    //加锁和解锁之间的代码块我们称之为临界区（Critical Section），
                    // 任何时候临界区最多只有一个线程能执行。
                    Counter0.count += 1;
                }   //synchronized代码块执行结束后自动释放锁
                /*
上面的代码表示用Counter.lock实例作为锁，两个线程在执行各自的synchronized(Counter.lock) { ... }代码块时，
必须先获得锁，才能进入代码块进行。执行结束后，在synchronized语句块结束会自动释放锁。
这样一来，对Counter.count变量进行读写就不可能同时进行。上述代码无论运行多少次，最终结果都是0。

使用synchronized解决了多线程同步访问共享变量的正确性问题。
但是，它的缺点是带来了性能下降。因为synchronized代码块无法并发执行。
此外，加锁和解锁需要消耗一定的时间，所以，synchronized会降低程序的执行效率。

我们来概括一下如何使用synchronized：
    * 找出修改共享变量的线程代码块；
    * 选择一个共享实例作为锁；
    * 使用synchronized(lockObject) { ... }。
在使用synchronized的时候，不必担心抛出异常。因为无论是否有异常，都会在synchronized结束处正确释放锁
*/
            }
        });
        Thread dec = new Thread(()->{
            for (int i=0; i<10000; i++) {
                synchronized(Counter0.lock) {
                    Counter0.count -= 1;
                }
            }
        });
        add.start();
        dec.start();
        add.join();
        dec.join();
        System.out.println(Counter0.count);
    }
}

class Counter0 {
    //Java程序使用synchronized关键字对一个对象进行加锁.被加锁的是个对象
    public static final Object lock = new Object();
    public static int count = 0;
}
